/**
* New BSD Licence
*
* Copyright (c) 2009, Aspect Foundation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

#ifndef ASPECT_ENGINE_H
#define ASPECT_ENGINE_H

// Defines
//#define LOG_QUIETLY // Prevents logger sending log messages to the console.
#define PI 3.14159265
#define FPS_ACCUMULATOR_SIZE 20

// Standard includes
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <stack>

// Include memory manager
//#include "mmgr.h"

// Windows includes
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <sys/stat.h>
#endif

// Apple includes for OGL
#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/gl.h>	// Header File For The OpenGL32 Library
#include <OpenGL/glu.h>	// Header File For The GLu32 Library
#else
// Everyone elses includes for OGL
#include <GL/glew.h>    // Header File For The GL Extention Wrangler
//#include <GL/gl.h>	// Header File For The OpenGL Library
//#include <GL/glu.h>	// Header File For The GLu Library
#endif

// SDL includes
#include <SDL/SDL.h>
//#include <SDL/SDL_opengl.h>

// Include TinyXML
#include "tinyxml.h"

// Include Ant Tweak Bar
#include <AntTweakBar.h>

// Include FreeType
#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
#include <freetype/ftoutln.h>
#include <freetype/fttrigon.h>

// Engine includes
#include "Macros.h"
#include "FileHelpers.h"
#include "LinkedList.h"
#include "Logger.h"
#include "Vec2.h"
#include "Vec3.h"
//#include "Matrix3x3.h" // Incomplete
#include "Math.h"
//#include "IRenderer.h" / Incomplete
#include "MRTManager.h"
#include "Camera.h"
#include "State.h"
#include "ResourceManagement.h"
#include "ImageLoader.h"
#include "Material.h"
#include "FreeType.h"
#include "Shader.h"
#include "Model.h"
#include "BaseGeometry.h"
#include "SceneObject.h"
#include "Scene.h"
#include "TweakBar.h"
#include "GUISystem.h"

namespace agtk {

/** Struct for specifying initialization params for the engine before calling the constructor.
	@author Tom Savage (DocSavage)
**/
struct EngineSetup
{
	/** Text in application frame. **/
	const char* m_czTitle;

	/** Width of window in pixels. **/
	int m_iWidth;

	/** Height of window in pixels. **/
	int m_iHeight;

	/** Colour depth of window (bits per pixel). 0 for default. Can also be 8, 16, 32. **/ 
	int m_iBpp;

	/** If true, the relevant fullscreen flags are set. **/
	bool m_bUseFullscreen;

	/** Engine setup constructor. Sets default values. **/
	EngineSetup(void) {
		m_czTitle = "Aspect Engine Application";
		m_iWidth = 800;
		m_iHeight = 600;
		m_bUseFullscreen = false;
	}
};

/** Engine class. Single point of contact for application.
	@author Tom Savage (DocSavage)
**/
class Engine
{
public:
	/** Constructor.
		@param setup Engine setup details.
	**/
	Engine(EngineSetup *setup);

	/** Destructor. **/
	~Engine(void);

	/** Initializes engine.
		@return bool True on success.
	**/
	bool Initialize(void);

	/** Gets the logger object. **/
	Logger* GetLogger(void);

	/** Runs engine. Calls MainLoop only if m_isLoaded = true. **/
	void Run(void);

	/** Uninitializes everything and quits the application.
		@param int Value to return.
	**/
	void Quit(int ret_val);

	/** Stops game loop. **/
	void Stop(void);

	/** Returns m_lElapsedTicks.
		@return long
	**/
	long GetElapsedTicks(void);
	
	/** Returns the current FPS. **/
	float GetFPS(void);

	/** Gets the window hidth. **/
	int GetWidth(void);
	
	/** Gets the window height. **/
	int GetHeight(void);

	/** Add a state to the linked list.
		@param state Pointer to a state object.
		@param change Changes to new state if true. Defaults to true.
	**/
	void AddState(State *state, bool change = true);

	/** Removes a state from the linked list.
		@param state Pointer to state to remove.
	**/
	void RemoveState(State *state);

	/** Changes to a state with the specified ID.
		@param unsigned long ID of requested state.
	**/
	void ChangeState(unsigned long id);

	/** Returns a pointer to the current state.
		@return State*
	**/
	State *GetCurrentState(void);
	
	/** Get a pointer to the model manager. **/
	ResourceManager<Model>* GetModelManager(void);
	
	/** Get a pointer to the material manager. **/
	ResourceManager<Material>* GetMaterialManager(void);

	/** Get the specified shader pass. **/
	Shader* GetShaderPass(unsigned int index);

	/** Gets the GUI system. **/
	GUISystem* GetGUISystem(void);

private:
	/** Begins main loop. **/
	void MainLoop(void);

	/** Handles input from devices, network, etc. **/
	void HandleInput(void);

	/** Does time calculations and calls m_currentState->Update(). **/
	void Update(void);

	/** Renders everything. Calls m_currentState->Render(). **/
	void Render(void);

private:
	/** Engine setup object for storing a copy of setup variables. **/
	EngineSetup *m_setup;

	/** If true, game loop will continue. **/
	bool m_bRun;

	/** If true, game loop will start. **/
	bool m_bIsLoaded;

	/** True if application is minimized. **/
	bool m_bMinimized;

	/** SDL video flags. **/
	int VideoFlags;

	/** SDL surface for rendering. **/
	SDL_Surface * MainWindow;

	/** Text in application frame. **/
	const char* m_czTitle;

	/** Width of window in pixels. **/
	int m_iWidth;

	/** Height of window in pixels. **/
	int m_iHeight;

	/** Colour depth of window (bits per pixel). 0 for default. Can also be 8, 16, 32. **/ 
	int m_iBpp;

	/** Last tick count. **/
	long m_lLastTick;
	
	/** Current FPS. **/
	float m_fCurrentFPS;
	
	/** Elapsed ticks this frame. **/
	long m_lElapsedMS;

	/** FPS Accumulator. **/
	float m_FPSAccumulator[FPS_ACCUMULATOR_SIZE];

	/** FPS Accumulator counter. **/
	int m_FPSAccumulatorCounter;

	/** GUI manager. **/
	GUISystem *m_guiSystem;

	/** Linked list of states. **/
	LinkedList< State > *m_states;

	/** Pointer to current state in list. **/
	State *m_currentState;

	/** True if state was changed this frame. **/
	bool m_bStateChanged;

	/** Logger. **/
	Logger *m_logger;
	
	/** Resource manager for models. **/
	ResourceManager<Model>* m_modelManager;
	
	/** Resource manager for materials. **/
	ResourceManager<Material>* m_materialManager;

	/** Shaders. **/
	Shader* m_shaderPasses[2];

	/** MRT Manager. **/
	MRTManager* m_MRTManager;

	/** Test tweak bar. **/
	TweakBar* m_testTweakBar;
};

// Define g_aspectEngine as a global pointer.
extern Engine *g_aspectEngine;

}

#endif